iT邦幫忙

2021 iThome 鐵人賽

DAY 16
1
自我挑戰組

JS30 學習日記系列 第 16

Day 16 - CSS Text Shadow Mouse Move Effect

  • 分享至 

  • xImage
  •  

前言

JS 30 是由加拿大的全端工程師 Wes Bos 免費提供的 JavaScript 簡單應用課程,課程主打 No FrameworksNo CompilersNo LibrariesNo Boilerplate 在30天的30部教學影片裡,建立30個JavaScript的有趣小東西。

另外,Wes Bos 也很無私地在 Github 上公開了所有 JS 30 課程的程式碼,有興趣的話可以去 fork 或下載。


本日目標

製作讓文字陰影跟著滑鼠一起移動的效果。


解析程式碼

HTML 部分

.hero內放入我們預計要用來產生文字陰影(Text Shadow)效果的文字(h1)。

h1上有一個特殊的屬性:contenteditable,表示<h1></h1>之間的內容是可以被修改的。

<div class="hero">
    <h1 contenteditable>?WOAH!</h1>
</div>

<h1></h1>之間的內容可被修改如下:

  • 修改前

  • 修改後

JS 部分

在實作文字陰影效果之前,我們要先取得.hero和內部的h1

const hero = document.querySelector('.hero');
const text = hero.querySelector('h1');

由於我們的目的是產生文字陰影隨著滑鼠移動的效果,所以在.hero上註冊mousemove 事件的監聽器並以shadow()進行事件處理。

hero.addEventListener('mousemove',shadow);

shadow() :

const { offsetWidth: width, offsetHeight: height} = hero; : 最初,我們必須先取得.herowidthheight,用來計算後續文字陰影的移動量。

let { offsetX: x, offsetY: y} = e; : 我們也必須知道現在滑鼠所在的座標。

注意,這裡我們使用的是 ES6 Destructuring Assignment(解構賦值)的語法所以不使用像是const width = hero.offsetWidth;const height = hero.offsetHeight;這種較繁瑣的寫法。

function shadow(e){
    //const width = hero.offsetWidth;
    //const height = hero.offsetHeight;
    const { offsetWidth: width, offsetHeight: height} = hero;
      
    //where the person's cursor was
    //let x = e.offsetX;
    //let y = e.offsetY;
    let { offsetX: x, offsetY: y} = e;
}

因為event.offsetXevent.offsetY取得的是滑鼠相對於事件源元素(srcElement)的X,Y坐標,所以當我們把滑鼠移動到h1得到的座標就會是以h1的左上角為(0,0)開始的位置。

這樣的位置是有問題的,我們原本要取得的應該是滑鼠在視窗裡面的位置(或說是滑鼠相對.hero的位置),所以必須要做一點修正。

我們在觸發mousemove event的 DOM 物件不是.hero的情況下(this !== e.target)進行座標修正,只要滑鼠處於h1內部,就分別把(x,y)加上h1相對.hero左方和上方的距離。

function shadow(e){
    /*上略...*/
    //if hovering h1 instead of hero, then modify the x and the y values
    if (this !== e.target){
        x = x + e.target.offsetLeft;
        y = y + e.target.offsetTop;
    }
}

接下來,我們要決定文字陰影實際上可以移動的距離和範圍。

宣告常數walk作為在(x,y)方向所能移動的最遠距離,這裡我們設為500,也就是向左或向右各250、向上或向下各250

const xWalk = Math.round((x / width * walk) - (walk / 2));,把.hero的中心點x 座標指定為0x的範圍從-250~250(視窗最左邊到最右邊)。

const yWalk = Math.round((y / height * walk) - (walk / 2));,把.hero的中心點y 座標指定為0y的範圍從-250~250(視窗最上面到最下面)。

結合兩者,畫面上的座標 : 左上角(-250,-250)、正中央(0,0)、右下角(250,250)

const walk = 500;

function shadow(e){
      /*上略...*/
      //how far the text shadow should actually go
      const xWalk = Math.round((x / width * walk) - (walk / 2));
      const yWalk = Math.round((y / height * walk) - (walk / 2));
}
  • TextShadow能移動的範圍 (以walk = 500為例)

決定TextShadow可以移動的範圍後,接下來只要設定TextShadow的移動方向和顏色就完成囉!

function shadow(e){
    /*上略...*/
    text.style.textShadow = `
        ${xWalk}px ${yWalk}px 0 rgba(255,0,255,0.7),
        ${xWalk * -1}px ${yWalk}px 0 rgba(0,255,255,0.7),
        ${yWalk}px ${xWalk * -1}px 0 rgba(0,255,0,0.7),
        ${yWalk * -1}px ${xWalk}px 0 rgba(0,0,255,0.7)
     `;
}

範例畫面:

補充資料:

contenteditable
[筆記] ES6: Destructuring Assignment 解構賦值的使用
JS一秒區分clientX,offsetX,screenX,pageX之間關係

範例網頁請點此


上一篇
Day 15 - LocalStorage and Event Delegation
下一篇
Day 17 - Sorting Band Names without articles
系列文
JS30 學習日記31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言